

package ru.samgtu.wst.plugin.xss;

import java.util.logging.Logger;
import java.util.Set;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.NoSuchElementException;

import ru.samgtu.wst.model.ConversationID;
import ru.samgtu.wst.model.ConversationModel;
import ru.samgtu.wst.model.Cookie;
import ru.samgtu.wst.model.FilteredConversationModel;
import ru.samgtu.wst.model.FrameworkModel;
import ru.samgtu.wst.model.HttpUrl;
import ru.samgtu.wst.model.Request;
import ru.samgtu.wst.model.Response;
import ru.samgtu.wst.plugin.AbstractPluginModel;


public class XSSModel extends AbstractPluginModel {

	private FrameworkModel _model;

	private ConversationModel _conversationModel, _suspectedConversationModel;

	private LinkedList toBeAnalyzedQueue = new LinkedList();

	private Logger _logger = Logger.getLogger(getClass().getName());

	private Set testedURLandParameterpairs = new HashSet();
	private Cookie cookie;
	private String xssTestString = "><script>a=/XSS BUG/; alert(a.source)</script>";

	/** Creates a new instance of ExtensionsModel */
	public XSSModel(FrameworkModel model) {
		_model = model;
		/*
		 * lower table with possibly vulnerable URLs
		 */
		_conversationModel = new FilteredConversationModel(model, model
				.getConversationModel()) {
			@Override
			public boolean shouldFilter(ConversationID id) {
				return !isXSSVulnerable(id);
			}
		};

		/*
		 * upper table with suspected URLs
		 */
		_suspectedConversationModel = new FilteredConversationModel(model,
				model.getConversationModel()) {
			@Override
			public boolean shouldFilter(ConversationID id) {
				return !isXSSSuspected(id);
			}
		};
	}

	public ConversationModel getVulnerableConversationModel() {
		return _conversationModel;
	}

	public ConversationModel getSuspectedConversationModel() {
		return _suspectedConversationModel;
	}

	public void markAsXSSSuspicious(ConversationID id, HttpUrl url,
			String location, String parameter) {
		_logger.info("test parameter v MarkASXXX" + id + " " + parameter);
		_model.addConversationProperty(id, "XSS-" + location, parameter);
		_model.addUrlProperty(url, "XSS-" + location, parameter);
	}

	public boolean isXSSSuspected(ConversationID id) {
		boolean suspect = false;
		suspect |= (_model.getConversationProperty(id, "XSS-GET") != null);
		suspect |= (_model.getConversationProperty(id, "XSS-POST") != null);
		return suspect;
	}

	public boolean isSuspected(HttpUrl url) {
		boolean suspect = false;
		suspect |= (_model.getUrlProperty(url, "XSS-GET") != null);
		suspect |= (_model.getUrlProperty(url, "XSS-POST") != null);
		return suspect;
	}

	public void setXSSVulnerable(ConversationID id, HttpUrl url) {
		_model.setUrlProperty(url, "XSS", "TRUE");
		_model.setConversationProperty(id, "XSS", "TRUE");
	}

	public boolean isXSSVulnerable(ConversationID id) {
		return "TRUE".equals(_model.getConversationProperty(id, "XSS"));
	}

	public boolean isXSSVulnerable(HttpUrl url) {
		return "TRUE".equals(_model.getUrlProperty(url, "XSS"));
	}

	public String[] getXSSSuspiciousParameters(ConversationID id, String where) {
		return _model.getConversationProperties(id, "XSS-" + where);
	}

	public String getXSSTestString() {
		return xssTestString;
	}

	public void setXSSTestString(String _xssTestString) {
		xssTestString = _xssTestString;
	}

	public Request getRequest(ConversationID id) {
		return _model.getRequest(id);
	}

	public Response getResponse(ConversationID id) {
		return _model.getResponse(id);
	}

	public synchronized void clearTestedURLandParameterpairs() {
		testedURLandParameterpairs = new HashSet();
	}

	private boolean isTested(Request req, String vulnParam) {
		HttpUrl url = req.getURL();
		return testedURLandParameterpairs.contains(url.getSHPP() + vulnParam);
	}

	public void enqueueRequest(Request req, String paramName) {
		synchronized (toBeAnalyzedQueue) {
			if (!isTested(req, paramName)) {
				toBeAnalyzedQueue.addLast(req);
				toBeAnalyzedQueue.notifyAll();
				testedURLandParameterpairs.add(req.getURL().getSHPP()
						+ paramName);
			}
		}
	}

	public Request dequeueRequest() {

		synchronized (toBeAnalyzedQueue) {
			try {
				while (toBeAnalyzedQueue.isEmpty()) {
					toBeAnalyzedQueue.wait();
					return null;
				}
				return (Request) toBeAnalyzedQueue.removeFirst();
			} catch (InterruptedException e) {
				return null;
			} catch (NoSuchElementException e) {
				return null;
			}
		}
	}

}
